package yusvr

import (
	"context"
	"encoding/json"
	"net/http"
	"time"

	"gitee.com/yscsky/yu"
	"gitee.com/yscsky/yu/prome"
	"gitee.com/yscsky/yu/yuresp"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/protobuf/proto"
)

// IEchoServer echo服务实现接口
type IEchoServer interface {
	yu.IServer
	Echo() *echo.Echo
	Health()
	Group(path string, m ...echo.MiddlewareFunc) *echo.Group
	JSON(c echo.Context, data any) error
	JsonOK(c echo.Context, data any) error
	JsonErr(c echo.Context, err error) error
	JsonMsg(c echo.Context, msg string) error
	PbOK(c echo.Context, m proto.Message) error
	GzipPbOK(c echo.Context, m proto.Message) error
	PbErr(c echo.Context, err error) error
	Promethous(name, pass string)
	PromeMetrics() echo.MiddlewareFunc
	BasicAuth(name, pass string) echo.MiddlewareFunc
	NoCache() echo.MiddlewareFunc
}

// EchoServer 使用echo框架的server
type echoServer struct {
	addr string
	name string
	e    *echo.Echo
}

// NewEchoServer 创建EchoServer
func NewEchoServer(name, addr string) IEchoServer {
	e := echo.New()
	e.Use(middleware.Recover(), middleware.Gzip())
	return &echoServer{
		addr: addr,
		name: name,
		e:    e,
	}
}

// OnStart 实现IServer接口
func (s *echoServer) OnStart() bool {
	yu.Logf("%s echo server start at %s", s.Info(), s.addr)
	if err := s.e.Start(s.addr); err != nil && err != http.ErrServerClosed {
		yu.LogErr(err, "Echo Start")
	}
	return true
}

// OnStop 实现IServer接口
func (s *echoServer) OnStop() {
	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	defer cancel()
	if err := s.e.Shutdown(ctx); err != nil {
		yu.LogErr(err, "Echo Shutdown")
	}
}

// Info 实现IServer接口
func (s *echoServer) Info() string {
	return s.name
}

// Echo 获取Ehco
func (s *echoServer) Echo() *echo.Echo {
	return s.e
}

// Health 健康检查接口，需要的话设置
func (s *echoServer) Health() {
	s.e.GET("health", func(c echo.Context) error { return s.JsonOK(c, "yes") })
}

// Group 创建echo.Group
func (s *echoServer) Group(path string, m ...echo.MiddlewareFunc) *echo.Group {
	return s.e.Group(path, m...)
}

// JSON 发送JSON
func (s *echoServer) JSON(c echo.Context, data any) error {
	c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
	c.Response().WriteHeader(http.StatusOK)
	return json.NewEncoder(c.Response()).Encode(data)
}

// JsonOK 反馈OK
func (s *echoServer) JsonOK(c echo.Context, data any) error {
	return s.JSON(c, yuresp.RespOK(data))
}

// JsonErr 反馈Err
func (s *echoServer) JsonErr(c echo.Context, err error) error {
	return s.JSON(c, yuresp.RespErr(err))
}

// JsonMsg 反馈发生错误信息
func (s *echoServer) JsonMsg(c echo.Context, msg string) error {
	return s.JSON(c, yuresp.RespMsg(yuresp.CodeErr, msg))
}

// PbOK 反馈OK
func (s *echoServer) PbOK(c echo.Context, m proto.Message) error {
	return yuresp.PbRespOK(c.Response(), m)
}

// GzipPbOK gzip反馈OK
func (s *echoServer) GzipPbOK(c echo.Context, m proto.Message) error {
	return yuresp.GzipPbRespOK(c.Response(), m)
}

// PbErr 反馈Err
func (s *echoServer) PbErr(c echo.Context, err error) error {
	return yuresp.PbRespError(c.Response(), err)
}

// Promethous 启动Promethous监听
func (s *echoServer) Promethous(name, pass string) {
	prome.InitPrometheus("YU", s.name)
	s.e.GET("metrics", s.promethousHandler, s.BasicAuth(name, pass))
}

// PromeMetrics prometheus metrics 中间件
func (s *echoServer) PromeMetrics() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			defer prome.PromeTrace(c.Request().URL.Path)()
			return next(c)
		}
	}
}

// BasicAuth 设置BasicAuth认证
func (s *echoServer) BasicAuth(name, pass string) echo.MiddlewareFunc {
	return middleware.BasicAuth(func(n, p string, c echo.Context) (bool, error) {
		return name == n && pass == p, nil
	})
}

// PromethousHandler 启动promethous http监听
func (s *echoServer) promethousHandler(c echo.Context) error {
	promhttp.Handler().ServeHTTP(c.Response(), c.Request())
	return nil
}

// NoCache 设置请求头为无缓存
func (s *echoServer) NoCache() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			middleware.CORS()
			c.Request().Header.Set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
			return next(c)
		}
	}
}
